home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / unix / tkUnix3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  13.0 KB  |  449 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkUnix3d.c --
  3.  *
  4.  *    This file contains the platform specific routines for
  5.  *    drawing 3d borders in the Motif style.
  6.  *
  7.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkUnix3d.c 1.3 96/11/20 14:24:38
  13.  */
  14.  
  15. #include <tk3d.h>
  16.  
  17. /*
  18.  * This structure is used to keep track of the extra colors used
  19.  * by Unix 3d borders.
  20.  */
  21.  
  22. typedef struct {
  23.     TkBorder info;
  24.     GC solidGC;        /* Used to draw solid relief. */
  25. } UnixBorder;
  26.  
  27. /*
  28.  *----------------------------------------------------------------------
  29.  *
  30.  * TkpGetBorder --
  31.  *
  32.  *    This function allocates a new TkBorder structure.
  33.  *
  34.  * Results:
  35.  *    Returns a newly allocated TkBorder.
  36.  *
  37.  * Side effects:
  38.  *    None.
  39.  *
  40.  *----------------------------------------------------------------------
  41.  */
  42.  
  43. TkBorder *
  44. TkpGetBorder()
  45. {
  46.     UnixBorder *borderPtr = (UnixBorder *) ckalloc(sizeof(UnixBorder));
  47.     borderPtr->solidGC = None;
  48.     return (TkBorder *) borderPtr;
  49. }
  50.  
  51.  
  52. /*
  53.  *----------------------------------------------------------------------
  54.  *
  55.  * TkpFreeBorder --
  56.  *
  57.  *    This function frees any colors allocated by the platform
  58.  *    specific part of this module.
  59.  *
  60.  * Results:
  61.  *    None.
  62.  *
  63.  * Side effects:
  64.  *    May deallocate some colors.
  65.  *
  66.  *----------------------------------------------------------------------
  67.  */
  68.  
  69. void
  70. TkpFreeBorder(borderPtr)
  71.     TkBorder *borderPtr;
  72. {
  73.     UnixBorder *unixBorderPtr = (UnixBorder *) borderPtr;
  74.     Display *display = DisplayOfScreen(borderPtr->screen);
  75.  
  76.     if (unixBorderPtr->solidGC != None) {
  77.     Tk_FreeGC(display, unixBorderPtr->solidGC);
  78.     }
  79. }
  80. /*
  81.  *--------------------------------------------------------------
  82.  *
  83.  * Tk_3DVerticalBevel --
  84.  *
  85.  *    This procedure draws a vertical bevel along one side of
  86.  *    an object.  The bevel is always rectangular in shape:
  87.  *            |||
  88.  *            |||
  89.  *            |||
  90.  *            |||
  91.  *            |||
  92.  *            |||
  93.  *    An appropriate shadow color is chosen for the bevel based
  94.  *    on the leftBevel and relief arguments.  Normally this
  95.  *    procedure is called first, then Tk_3DHorizontalBevel is
  96.  *    called next to draw neat corners.
  97.  *
  98.  * Results:
  99.  *    None.
  100.  *
  101.  * Side effects:
  102.  *    Graphics are drawn in drawable.
  103.  *
  104.  *--------------------------------------------------------------
  105.  */
  106.  
  107. void
  108. Tk_3DVerticalBevel(tkwin, drawable, border, x, y, width, height,
  109.     leftBevel, relief)
  110.     Tk_Window tkwin;        /* Window for which border was allocated. */
  111.     Drawable drawable;        /* X window or pixmap in which to draw. */
  112.     Tk_3DBorder border;        /* Token for border to draw. */
  113.     int x, y, width, height;    /* Area of vertical bevel. */
  114.     int leftBevel;        /* Non-zero means this bevel forms the
  115.                  * left side of the object;  0 means it
  116.                  * forms the right side. */
  117.     int relief;            /* Kind of bevel to draw.  For example,
  118.                  * TK_RELIEF_RAISED means interior of
  119.                  * object should appear higher than
  120.                  * exterior. */
  121. {
  122.     TkBorder *borderPtr = (TkBorder *) border;
  123.     GC left, right;
  124.     Display *display = Tk_Display(tkwin);
  125.  
  126.     if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
  127.     TkpGetShadows(borderPtr, tkwin);
  128.     }
  129.  
  130.     if (relief == TK_RELIEF_RAISED) {
  131.     XFillRectangle(display, drawable, 
  132.         (leftBevel) ? borderPtr->lightGC : borderPtr->darkGC,
  133.         x, y, (unsigned) width, (unsigned) height);
  134.     } else if (relief == TK_RELIEF_SUNKEN) {
  135.     XFillRectangle(display, drawable, 
  136.         (leftBevel) ? borderPtr->darkGC : borderPtr->lightGC,
  137.         x, y, (unsigned) width, (unsigned) height);
  138.     } else if (relief == TK_RELIEF_RIDGE) {
  139.     int half;
  140.  
  141.     left = borderPtr->lightGC;
  142.     right = borderPtr->darkGC;
  143.     ridgeGroove:
  144.     half = width/2;
  145.     if (!leftBevel && (width & 1)) {
  146.         half++;
  147.     }
  148.     XFillRectangle(display, drawable, left, x, y, (unsigned) half,
  149.         (unsigned) height);
  150.     XFillRectangle(display, drawable, right, x+half, y,
  151.         (unsigned) (width-half), (unsigned) height);
  152.     } else if (relief == TK_RELIEF_GROOVE) {
  153.     left = borderPtr->darkGC;
  154.     right = borderPtr->lightGC;
  155.     goto ridgeGroove;
  156.     } else if (relief == TK_RELIEF_FLAT) {
  157.     XFillRectangle(display, drawable, borderPtr->bgGC, x, y,
  158.         (unsigned) width, (unsigned) height);
  159.     } else if (relief == TK_RELIEF_SOLID) {
  160.     UnixBorder *unixBorderPtr = (UnixBorder *) borderPtr;
  161.     if (unixBorderPtr->solidGC == None) {
  162.         XGCValues gcValues;
  163.  
  164.         gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
  165.         unixBorderPtr->solidGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  166.     }
  167.     XFillRectangle(display, drawable, unixBorderPtr->solidGC, x, y,
  168.         (unsigned) width, (unsigned) height);
  169.     }
  170. }
  171.  
  172. /*
  173.  *--------------------------------------------------------------
  174.  *
  175.  * Tk_3DHorizontalBevel --
  176.  *
  177.  *    This procedure draws a horizontal bevel along one side of
  178.  *    an object.  The bevel has mitered corners (depending on
  179.  *    leftIn and rightIn arguments).
  180.  *
  181.  * Results:
  182.  *    None.
  183.  *
  184.  * Side effects:
  185.  *    None.
  186.  *
  187.  *--------------------------------------------------------------
  188.  */
  189.  
  190. void
  191. Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, height,
  192.     leftIn, rightIn, topBevel, relief)
  193.     Tk_Window tkwin;        /* Window for which border was allocated. */
  194.     Drawable drawable;        /* X window or pixmap in which to draw. */
  195.     Tk_3DBorder border;        /* Token for border to draw. */
  196.     int x, y, width, height;    /* Bounding box of area of bevel.  Height
  197.                  * gives width of border. */
  198.     int leftIn, rightIn;    /* Describes whether the left and right
  199.                  * edges of the bevel angle in or out as
  200.                  * they go down.  For example, if "leftIn"
  201.                  * is true, the left side of the bevel
  202.                  * looks like this:
  203.                  *    ___________
  204.                  *     __________
  205.                  *      _________
  206.                  *       ________
  207.                  */
  208.     int topBevel;        /* Non-zero means this bevel forms the
  209.                  * top side of the object;  0 means it
  210.                  * forms the bottom side. */
  211.     int relief;            /* Kind of bevel to draw.  For example,
  212.                  * TK_RELIEF_RAISED means interior of
  213.                  * object should appear higher than
  214.                  * exterior. */
  215. {
  216.     TkBorder *borderPtr = (TkBorder *) border;
  217.     Display *display = Tk_Display(tkwin);
  218.     int bottom, halfway, x1, x2, x1Delta, x2Delta;
  219.     UnixBorder *unixBorderPtr = (UnixBorder *) borderPtr;
  220.     GC topGC = None, bottomGC = None;
  221.                 /* Initializations needed only to prevent
  222.                  * compiler warnings. */
  223.  
  224.     if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT) &&
  225.         (relief != TK_RELIEF_SOLID)) {
  226.     TkpGetShadows(borderPtr, tkwin);
  227.     }
  228.  
  229.     /*
  230.      * Compute a GC for the top half of the bevel and a GC for the
  231.      * bottom half (they're the same in many cases).
  232.      */
  233.  
  234.     switch (relief) {
  235.     case TK_RELIEF_FLAT:
  236.         topGC = bottomGC = borderPtr->bgGC;
  237.         break;
  238.     case TK_RELIEF_GROOVE:
  239.         topGC = borderPtr->darkGC;
  240.         bottomGC = borderPtr->lightGC;
  241.         break;
  242.     case TK_RELIEF_RAISED:
  243.         topGC = bottomGC =
  244.             (topBevel) ? borderPtr->lightGC : borderPtr->darkGC;
  245.         break;
  246.     case TK_RELIEF_RIDGE:
  247.         topGC = borderPtr->lightGC;
  248.         bottomGC = borderPtr->darkGC;
  249.         break;
  250.     case TK_RELIEF_SOLID:
  251.         if (unixBorderPtr->solidGC == None) {
  252.         XGCValues gcValues;
  253.  
  254.         gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
  255.         unixBorderPtr->solidGC = Tk_GetGC(tkwin, GCForeground,
  256.             &gcValues);
  257.         }
  258.         XFillRectangle(display, drawable, unixBorderPtr->solidGC, x, y,
  259.         (unsigned) width, (unsigned) height);
  260.         return;
  261.     case TK_RELIEF_SUNKEN:
  262.         topGC = bottomGC =
  263.             (topBevel) ? borderPtr->darkGC : borderPtr->lightGC;
  264.         break;
  265.     }
  266.  
  267.     /*
  268.      * Compute various other geometry-related stuff.
  269.      */
  270.  
  271.     x1 = x;
  272.     if (!leftIn) {
  273.     x1 += height;
  274.     }
  275.     x2 = x+width;
  276.     if (!rightIn) {
  277.     x2 -= height;
  278.     }
  279.     x1Delta = (leftIn) ? 1 : -1;
  280.     x2Delta = (rightIn) ? -1 : 1;
  281.     halfway = y + height/2;
  282.     if (!topBevel && (height & 1)) {
  283.     halfway++;
  284.     }
  285.     bottom = y + height;
  286.  
  287.     /*
  288.      * Draw one line for each y-coordinate covered by the bevel.
  289.      */
  290.  
  291.     for ( ; y < bottom; y++) {
  292.     /*
  293.      * In some weird cases (such as large border widths for skinny
  294.      * rectangles) x1 can be >= x2.  Don't draw the lines
  295.      * in these cases.
  296.      */
  297.  
  298.     if (x1 < x2) {
  299.         XFillRectangle(display, drawable,
  300.         (y < halfway) ? topGC : bottomGC, x1, y,
  301.         (unsigned) (x2-x1), (unsigned) 1);
  302.     }
  303.     x1 += x1Delta;
  304.     x2 += x2Delta;
  305.     }
  306. }
  307.  
  308. /*
  309.  *----------------------------------------------------------------------
  310.  *
  311.  * TkpGetShadows --
  312.  *
  313.  *    This procedure computes the shadow colors for a 3-D border
  314.  *    and fills in the corresponding fields of the Border structure.
  315.  *    It's called lazily, so that the colors aren't allocated until
  316.  *    something is actually drawn with them.  That way, if a border
  317.  *    is only used for flat backgrounds the shadow colors will
  318.  *    never be allocated.
  319.  *
  320.  * Results:
  321.  *    None.
  322.  *
  323.  * Side effects:
  324.  *    The lightGC and darkGC fields in borderPtr get filled in,
  325.  *    if they weren't already.
  326.  *
  327.  *----------------------------------------------------------------------
  328.  */
  329.  
  330. void
  331. TkpGetShadows(borderPtr, tkwin)
  332.     TkBorder *borderPtr;        /* Information about border. */
  333.     Tk_Window tkwin;        /* Window where border will be used for
  334.                  * drawing. */
  335. {
  336.     XColor lightColor, darkColor;
  337.     int stressed, tmp1, tmp2;
  338.     XGCValues gcValues;
  339.  
  340.     if (borderPtr->lightGC != None) {
  341.     return;
  342.     }
  343.     stressed = TkpCmapStressed(tkwin, borderPtr->colormap);
  344.  
  345.     /*
  346.      * First, handle the case of a color display with lots of colors.
  347.      * The shadow colors get computed using whichever formula results
  348.      * in the greatest change in color:
  349.      * 1. Lighter shadow is half-way to white, darker shadow is half
  350.      *    way to dark.
  351.      * 2. Lighter shadow is 40% brighter than background, darker shadow
  352.      *    is 40% darker than background.
  353.      */
  354.  
  355.     if (!stressed && (Tk_Depth(tkwin) >= 6)) {
  356.     /*
  357.      * This is a color display with lots of colors.  For the dark
  358.      * shadow, cut 40% from each of the background color components.
  359.      * For the light shadow, boost each component by 40% or half-way
  360.      * to white, whichever is greater (the first approach works
  361.      * better for unsaturated colors, the second for saturated ones).
  362.      */
  363.  
  364.     darkColor.red = (60 * (int) borderPtr->bgColorPtr->red)/100;
  365.     darkColor.green = (60 * (int) borderPtr->bgColorPtr->green)/100;
  366.     darkColor.blue = (60 * (int) borderPtr->bgColorPtr->blue)/100;
  367.     borderPtr->darkColorPtr = Tk_GetColorByValue(tkwin, &darkColor);
  368.     gcValues.foreground = borderPtr->darkColorPtr->pixel;
  369.     borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  370.  
  371.     /*
  372.      * Compute the colors using integers, not using lightColor.red
  373.      * etc.: these are shorts and may have problems with integer
  374.      * overflow.
  375.      */
  376.  
  377.     tmp1 = (14 * (int) borderPtr->bgColorPtr->red)/10;
  378.     if (tmp1 > MAX_INTENSITY) {
  379.         tmp1 = MAX_INTENSITY;
  380.     }
  381.     tmp2 = (MAX_INTENSITY + (int) borderPtr->bgColorPtr->red)/2;
  382.     lightColor.red = (tmp1 > tmp2) ? tmp1 : tmp2;
  383.     tmp1 = (14 * (int) borderPtr->bgColorPtr->green)/10;
  384.     if (tmp1 > MAX_INTENSITY) {
  385.         tmp1 = MAX_INTENSITY;
  386.     }
  387.     tmp2 = (MAX_INTENSITY + (int) borderPtr->bgColorPtr->green)/2;
  388.     lightColor.green = (tmp1 > tmp2) ? tmp1 : tmp2;
  389.     tmp1 = (14 * (int) borderPtr->bgColorPtr->blue)/10;
  390.     if (tmp1 > MAX_INTENSITY) {
  391.         tmp1 = MAX_INTENSITY;
  392.     }
  393.     tmp2 = (MAX_INTENSITY + (int) borderPtr->bgColorPtr->blue)/2;
  394.     lightColor.blue = (tmp1 > tmp2) ? tmp1 : tmp2;
  395.     borderPtr->lightColorPtr = Tk_GetColorByValue(tkwin, &lightColor);
  396.     gcValues.foreground = borderPtr->lightColorPtr->pixel;
  397.     borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  398.     return;
  399.     }
  400.  
  401.     if (borderPtr->shadow == None) {
  402.     borderPtr->shadow = Tk_GetBitmap((Tcl_Interp *) NULL, tkwin,
  403.         Tk_GetUid("gray50"));
  404.     if (borderPtr->shadow == None) {
  405.         panic("TkpGetShadows couldn't allocate bitmap for border");
  406.     }
  407.     }
  408.     if (borderPtr->visual->map_entries > 2) {
  409.     /*
  410.      * This isn't a monochrome display, but the colormap either
  411.      * ran out of entries or didn't have very many to begin with.
  412.      * Generate the light shadows with a white stipple and the
  413.      * dark shadows with a black stipple.
  414.      */
  415.  
  416.     gcValues.foreground = borderPtr->bgColorPtr->pixel;
  417.     gcValues.background = BlackPixelOfScreen(borderPtr->screen);
  418.     gcValues.stipple = borderPtr->shadow;
  419.     gcValues.fill_style = FillOpaqueStippled;
  420.     borderPtr->darkGC = Tk_GetGC(tkwin,
  421.         GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  422.     gcValues.background = WhitePixelOfScreen(borderPtr->screen);
  423.     borderPtr->lightGC = Tk_GetGC(tkwin,
  424.         GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  425.     return;
  426.     }
  427.  
  428.     /*
  429.      * This is just a measly monochrome display, hardly even worth its
  430.      * existence on this earth.  Make one shadow a 50% stipple and the
  431.      * other the opposite of the background.
  432.      */
  433.  
  434.     gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
  435.     gcValues.background = BlackPixelOfScreen(borderPtr->screen);
  436.     gcValues.stipple = borderPtr->shadow;
  437.     gcValues.fill_style = FillOpaqueStippled;
  438.     borderPtr->lightGC = Tk_GetGC(tkwin,
  439.         GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  440.     if (borderPtr->bgColorPtr->pixel
  441.         == WhitePixelOfScreen(borderPtr->screen)) {
  442.     gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
  443.     borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  444.     } else {
  445.     borderPtr->darkGC = borderPtr->lightGC;
  446.     borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  447.     }
  448. }
  449.